using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Athena;
using Athena.Tools;
using Athena.Objects;
using Athena.Core;
using Athena.Plugins;
using WeifenLuo.WinFormsUI.Docking;

namespace Cells
{
    public partial class Form1 : Athena.Tools.IGUITool
    {

        public override void SetupToolStrip(ToolStrip oStrip)
        {
            ToolStripButton oButton = new ToolStripButton();
            oButton.Text = Text;
            oButton.ToolTipText = "Stochastic repressilator model with multiple cells";
            oButton.Click += new EventHandler(ShowHide_Click);
            oStrip.Items.Add(oButton);
            _bHasContextMenuItems = false;
            _bHasMenuItems = false;
            _bRequiresNewToolWindow = false;
        }
        public override bool HasMenuItems
        {
            get
            {
                return false;
            }
        }
        public override void SetupDockPanel(WeifenLuo.WinFormsUI.Docking.DockPanel oPanel)
        {
            this.DockPanel = oPanel;
            DockState = WeifenLuo.WinFormsUI.Docking.DockState.DockLeft;
            Hide();
        }

        public override void ShowHide_Click(object sender, EventArgs e)
        {
            if (IsHidden)
            {
                //DockState = WeifenLuo.WinFormsUI.Docking.DockState.DockRight;
                Show();
            }
            else
            {
                Hide();
            }
        }

        public Form1()
        {
            InitializeComponent();

            SetStyle(ControlStyles.AllPaintingInWmPaint |
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.ResizeRedraw |
                ControlStyles.UserPaint, true);

            Text = "Repressilator";
            _bHasContextMenuItems = false;
            _bHasMenuItems = false;
            _bRequiresNewToolWindow = false;
            ToolManager.Instance.RegisterTool(Text, this);
        }

        static Module Repressilator()
        {
            Gene lacI = new Gene("lacI", ""),
                 tetR = new Gene("tetR", ""),
                 cL = new Gene("cL", ""),
                 gfp = new Gene("gfp", "");

            Promoter pLac = new Promoter("pLac", ""),
                     pTet = new Promoter("pTet", ""),
                     pCl = new Promoter("pCl", ""),
                     pGfp = new Promoter("pGfp", "");

            Terminator t1 = new Terminator(),
                       t2 = new Terminator(),
                       t3 = new Terminator();

            Species LacI = new Species("protein", "LacI", 2),
                    TetR = new Species("protein", "TetR", 3),
                    CL = new Species("protein", "CL", 4),
                    GFP = new Species("protein", "GFP", 0);

            Edge laciProduction = new Edge(lacI, LacI, "lacI"),
                 tetrProduction = new Edge(tetR, TetR, "tetR"),
                 clProduction = new Edge(cL, CL, "cL"),
                 gfpProduction = new Edge(gfp, GFP, "gfp");

            Module mod = new Module("module", "Repressilator");

            Part.Connect(pLac, lacI, t1, pTet, tetR, t2, pCl, cL, t3, pGfp, gfp);

            mod.AddItem(pLac, pTet, pCl, pGfp, lacI, tetR, cL, gfp, t1, t2, t3, LacI, TetR, CL, GFP, laciProduction, tetrProduction, clProduction, gfpProduction);

            /*
            pLac.Right = lacI;
            pTet.Right = tetR;
            pCl.Right = cL;
            pGfp.Right = gfp;
            */
            pLac.PoPS.Rate = "10 / (1 + CL^3 )";  //TranscriptionRate.NOT(new Node[] { CL }).ToString()
            pTet.PoPS.Rate = "10 / (1 + LacI^2)";
            pCl.PoPS.Rate = "10 / (1 + TetR^3)";
            pGfp.PoPS.Rate = "10 / (1 + LacI^2)";

            mod.Degradation("k0",TetR,CL,LacI,GFP);
            mod.SetParameter("k0", 0.1);

            //mod.AddItem(new Edge(LacI, Module.Empty, "k0*LacI*IPTG"));
            mod.Update();

            return mod;
        }

        public void MakeCells(int numCells, int iptgConc)
        {
            Random rUnif = new Random();

            //Species IPTG = new Species("molecule", "IPTG", true, iptgConc);
            
            //CurrentModel.BackEndModel.AddItem(IPTG);

            int width = Utility.Panel.Width;
            float sz = (float)cellSz.Value;
            int numCols = (int)(width / sz);
            int n = 0;
            int i=0;
            while (n < numCells)
            {
                for (int j = 0; j < numCols && n < numCells; ++j)
                {
                    Module mod = Repressilator();
                    //mod.SetParameter("IPTG", iptgConc);

                    CompartmentGlyph cellDrawable = new CompartmentGlyph();

                    cellDrawable.FilledView = true;
                    cellDrawable.Location = new PointF(j * sz + 5, i * sz + 5);
                    cellDrawable.Dimensions = new SizeF(sz/2, sz/2);
                    cellDrawable.ShowText = false;

                    Compartment cell = new Compartment();
                    cell.AddItem(mod);
                    
                    cellDrawable.Item = cell;
                    cellDrawable.ColorStart = 
                    cellDrawable.ColorEnd = Color.FromArgb(0, 0, 0);

                    CurrentModel.AddToModel(cellDrawable,false,false,false,false);                   

                    ++n;
                }
                ++i;
            }
            Utility.Refresh();
        }

        double[,] data = null;
        ArrayList list = null;
        Hashtable nameToParent = null;

        private void simButton_Click(object sender, EventArgs e)
        {
            if (CurrentModel.Drawables.Count > 0)
            {
                DialogResult dialogResult = MessageBox.Show("Clear the current model?", "", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
                if (dialogResult != DialogResult.OK)
                    return;
                else
                    CurrentModel.Clear(true);
            }

            MakeCells((int)numCells.Value,(int)(numIptg.Value));
            
            CurrentModel.OnModelChanged(EventArgs.Empty);
            labelStatus.Text = "initializing...";
            this.Refresh();

            //StochasticSimulator.Simulator simulator = new StochasticSimulator.Simulator();
            //StochasticSimulator.Simulator simulator = StochasticSimulator.SimTool.simulator;

            Athena.Plugins.Simulator simulator = Athena.ToolManager.Instance.Simulator;
            simulator.CurrentModule = CurrentModel.BackEndModel;
            
            list = new ArrayList();
            list.Add("Time");

            Hashtable allitems = CurrentModel.BackEndModel.AllItems;
            nameToParent = new Hashtable();

            foreach (string str in allitems.Keys)
            {
                Species s = allitems[str] as Species;
                if (s != null && s.ID == "GFP")
                {
                    list.Add(str);
                    nameToParent[str] = s.ParentOfType(typeof(Compartment));
                }
            }

            double endTime = (double)maxTime.Value;
            simulator.setNumPoints((int)endTime);
            simulator.setTimeStart(0);
            simulator.setTimeEnd(endTime);
            simulator.setSelectionList(list);

            labelStatus.Text = "simulating...";
            this.Refresh();

            data = simulator.simulate();
            list = simulator.getSelectionList();

            labelStatus.Text = "finished simulating";
            this.Refresh();
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            if (nameToParent == null || list == null || data == null) return;
            int time = 0;
            for (int i = 0; i < data.GetLength(0); ++i)
            {
                //Thread.Sleep((int)(5* - data[i - 1, 0]));
                if (data[i, 0] > time)
                {
                    for (int j = 1; j < list.Count; ++j)
                    {
                        Compartment c = nameToParent[list[j]] as Compartment;
                        if (c != null && c.Drawable != null)
                        {
                            int g = (int)(data[i, j] * 255f / 10f);
                            if (g > 255) g = 255;
                            c.Drawable.ColorStart = c.Drawable.ColorEnd = Color.FromArgb(0, g, 0);
                        }
                    }
                    labelStatus.Text = string.Format("time = {0}", time);
                    this.Refresh();
                    Utility.Refresh();
                    ++time;
                }
            }
            time = 0;
        }

    }
}